package com.client;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;

import com.client.gui.DoodleTextArea;
import com.packages.ServerPackageHandler;
import com.sendables.Cursor;
import com.sendables.Paintable;
import com.sendables.Sendable;
import com.sendables.Shape;

public class Monitor {
	public int													status							= START;

	public static final int										START							= 0x0000;

	public static final int										SEND_ID_REQ						= 0x0E00;
	public static final int										AWAIT_ID_ANS					= 0x0F00 | ServerPackageHandler.ID_ANS;

	public static final int										SEND_ROOM_LIST_REQ				= 0x0100;
	public static final int										AWAITING_ROOM_LIST_ANS			= 0x0200 | ServerPackageHandler.LIST_ROOM_ANS;
	public static final int										AWAITING_USER_ROOM_SELECT		= 0x0300;
	public static final int										AWAITING_JOIN_ROOM_ANS			= 0x0400 | ServerPackageHandler.JOIN_ROOM_ANS;
	public static final int										AWAITING_DRAWABLE				= 0x0500 | ServerPackageHandler.SENDABLE;

	public static final int										AWAITING_USER_JOIN_OR_CREATE	= 0x0600;
	public static final int										AWAITING_USER_ROOM_CREATE		= 0x0700;
	public static final int										AWAITING_USER_ROOM_CREATE_ANS	= 0x0800 | ServerPackageHandler.CREATE_ROOM_ANS;
	public static final int										AWAIT_USER_JOIN_OR_QUIT			= 0x0B00;

	/* new states, not implemented yet */
	public static final int										SEND_LEAVE_ROOM					= 0x0900;
	public static final int										AWAITING_LEAVE_ROOM_ACK			= 0x0A00 | ServerPackageHandler.LEAVE_ROOM_ACK;
	public static final int										SEND_DISCONNECT					= 0x0C00;
	public static final int										AWAIT_DISCONNECT				= 0x0D00 | ServerPackageHandler.DISCONNECT_ACK;

	private Image												img;
	private Image												img2;
	private Graphics											g;
	private Graphics											g2;
	private DoodleTextArea										a;
	private LinkedList<byte[]>									messageInBuffer;
	private LinkedList<Sendable>								messageOutBuffer;
	private Map<Integer, Cursor>								cursorMap;
	private Map<Integer, Map<Integer, LinkedList<Paintable>>>	tempMap;
	private Map<Integer, LinkedList<Paintable>>					undoBuffer;

	public Monitor(int width, int height, ClientMain cm, DoodleTextArea a)
	{
		messageInBuffer = new LinkedList<byte[]>();
		messageOutBuffer = new LinkedList<Sendable>();
		cursorMap = new HashMap<Integer, Cursor>();
		tempMap = new HashMap<Integer, Map<Integer, LinkedList<Paintable>>>();
		undoBuffer = new HashMap<Integer, LinkedList<Paintable>>();
		img = cm.createImage(width, height);
		img2 = cm.createImage(width, height);
		g = img.getGraphics();
		g2 = img2.getGraphics();
		g.setColor(Color.black);
		g.fillRect(0, 0, width, height);
		g.setColor(Color.white);
		g2.setColor(Color.black);
		g2.fillRect(0, 0, width, height);
		g2.setColor(Color.white);
		this.a = a;
		status = SEND_ID_REQ;
	}

	public synchronized Sendable getOutgoing()
	{
		while (messageOutBuffer.isEmpty())
		{
			try
			{
				wait();
			} catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}
		Sendable s = messageOutBuffer.pop();
		notifyAll();
		return s;
	}

	public synchronized void putOutgoint(Sendable s)
	{
		messageOutBuffer.add(s);
		notifyAll();
	}

	public synchronized int getStatus()
	{
		return status;
	}

	public synchronized int getStatus(int prevStatus)
	{
		while (prevStatus == status && prevStatus != AWAITING_DRAWABLE)
		{
			try
			{
				wait();
			} catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}
		return status;
	}

	public synchronized void setStatus(int status)
	{
		this.status = status;
		notifyAll();
	}

	public synchronized byte[] get()
	{
		while (messageInBuffer.isEmpty())
		{
			try
			{
				wait();
			} catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}
		byte[] b = messageInBuffer.pop();
		notifyAll();
		return b;
	}

	public synchronized void put(byte[] b)
	{
		messageInBuffer.push(b);
		notifyAll();
	}

	public synchronized void setCursor(Cursor s)
	{
		cursorMap.put(s.getId(), s);
	}

	public synchronized Image getImage()
	{
		g2.drawImage(img, 0, 0, null);
		for (Entry<Integer, Map<Integer, LinkedList<Paintable>>> e : tempMap.entrySet())
		{
			for (Entry<Integer, LinkedList<Paintable>> ee : e.getValue().entrySet())
			{
				for (Paintable p : ee.getValue())
					p.paint(g2);
			}
		}
		for (Entry<Integer, LinkedList<Paintable>> p : undoBuffer.entrySet())
		{
			for (Paintable pp : p.getValue())
			{
				pp.paint(g2);
			}
		}
		for (Entry<Integer, Cursor> e : cursorMap.entrySet())
		{
			e.getValue().paint(g2);
		}
		return img2;
	}

	public synchronized Graphics getGraphics()
	{
		return g;
	}

	public DoodleTextArea getTextArea()
	{
		return a;
	}

	public synchronized void removeFromTempBuffer(int id, int type)
	{
		if (!tempMap.containsKey(id))
		{
			return;
		}
		tempMap.get(id).get(type).clear();
	}

	public synchronized void postTempBuffer(Paintable d, int id, int type)
	{
		if (!tempMap.containsKey(id))
		{
			tempMap.put(id, new HashMap<Integer, LinkedList<Paintable>>());
		}
		if (!tempMap.get(id).containsKey(type))
		{
			tempMap.get(id).put(type, new LinkedList<Paintable>());
		}
		if (type != Shape.LINE && tempMap.get(id).get(type).size() > 1)
		{
			tempMap.get(id).get(type).pop();
		}
		tempMap.get(id).get(type).push(d);
	}

	public synchronized void postUndoBuffer(int id, Paintable p)
	{
		if (!undoBuffer.containsKey(id))
		{
			undoBuffer.put(id, new LinkedList<Paintable>());
		}
		if (undoBuffer.get(id).size() > 10)
		{
			undoBuffer.get(id).removeLast().paint(g);
			System.out.println("To big, removing!");
		}
		undoBuffer.get(id).addFirst(p);
	}

}
